<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"example.com","root":"/","scheme":"Mist","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
  </script>

  <meta name="description" content="学习区块链额工作原理的最快方法就是通过自己创建一个区块链 你在观看本文的原因正如你像我一样对加密货币的兴起感到振奋。你希望知道区块链的工作原理——支撑其运行的背后的基础技术。 但是理解区块链并不是一件简单的事情，至少对于我是这样。观看了大量的视频和教程，但非常少的例子参考让我学习起来非常艰难。">
<meta property="og:type" content="article">
<meta property="og:title" content="从零开始用Python创建一条区块链">
<meta property="og:url" content="http://example.com/2021/09/29/learn-blockchains-by-building-one/index.html">
<meta property="og:site_name" content="尼奥的乱码">
<meta property="og:description" content="学习区块链额工作原理的最快方法就是通过自己创建一个区块链 你在观看本文的原因正如你像我一样对加密货币的兴起感到振奋。你希望知道区块链的工作原理——支撑其运行的背后的基础技术。 但是理解区块链并不是一件简单的事情，至少对于我是这样。观看了大量的视频和教程，但非常少的例子参考让我学习起来非常艰难。">
<meta property="og:locale">
<meta property="og:image" content="http://example.com/2021/09/29/learn-blockchains-by-building-one/1.png">
<meta property="og:image" content="http://example.com/2021/09/29/learn-blockchains-by-building-one/2.png">
<meta property="article:published_time" content="2021-09-29T01:50:51.712Z">
<meta property="article:modified_time" content="2021-09-29T01:50:51.713Z">
<meta property="article:author" content="李工">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://example.com/2021/09/29/learn-blockchains-by-building-one/1.png">

<link rel="canonical" href="http://example.com/2021/09/29/learn-blockchains-by-building-one/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-Hans'
  };
</script>

  <title>从零开始用Python创建一条区块链 | 尼奥的乱码</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="Toggle navigation bar">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">尼奥的乱码</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>Home</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>Archives</a>

  </li>
        <li class="menu-item menu-item-首页">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-编程">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>编程</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-Hans">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/29/learn-blockchains-by-building-one/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="李工">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="尼奥的乱码">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          从零开始用Python创建一条区块链
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2021-09-29 09:50:51" itemprop="dateCreated datePublished" datetime="2021-09-29T09:50:51+08:00">2021-09-29</time>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <p>学习区块链额工作原理的最快方法就是通过自己创建一个区块链</p>
<p>你在观看本文的原因正如你像我一样对加密货币的兴起感到振奋。你希望知道区块链的工作原理——支撑其运行的背后的基础技术。</p>
<p>但是理解区块链并不是一件简单的事情，至少对于我是这样。观看了大量的视频和教程，但非常少的例子参考让我学习起来非常艰难。</p>
<span id="more"></span>

<p>我喜欢一边学习一边实践。这强制我学习知识要点通过代码。<br>I like learning by doing. It forces me to deal with the subject matter at a code level, which gets it sticking. If you do the same, at the end of this guide you’ll have a functioning Blockchain with a solid grasp of how they work.</p>
<p>在你开始之前。。。</p>
<p>请记住一个区块链是一个顺序的，不可变的链，上门存储的记录叫做区块。区块能包含交易，文件，和其它任意类型的数据。但最重要的是这些区块是通过hash值链接在一起的。</p>
<p>如果你不是很清楚什么是hash，这里有一些解释。</p>
<p>这篇教程的目标读者群体：你应该能轻松的读/写一些基础的python代码，同时能理解HTTP请求是怎样工作的，因为我们将会讨论我们基于HTTP的区块链.</p>
<p>我需要安装什么？确保已经安装了Python 3.6+（连同pip）。同样需要安装Flask和request库：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install Flask==<span class="number">0.12</span><span class="number">.2</span> requests==<span class="number">2.18</span><span class="number">.4</span> </span><br></pre></td></tr></table></figure>

<p>哦，你还需要一个HTTP客户端，比如Postman或者cURL。</p>
<p>最终代码在哪里？源代码在这里。</p>
<h2 id="第一步：创建一个区块链"><a href="#第一步：创建一个区块链" class="headerlink" title="第一步：创建一个区块链"></a>第一步：创建一个区块链</h2><p>打开你最喜欢的文本编辑器或者IDE，我自己喜欢PyCharm，创建一个新文件，叫做blockchain.py。我们将只会使用这一个源文件。</p>
<h3 id="表现一个区块链"><a href="#表现一个区块链" class="headerlink" title="表现一个区块链"></a>表现一个区块链</h3><p>我们将创建一个区块链，其构造器将创建一个初始的空列表（用来存储我们的区块链数据），XXX,下面是我们类型的设计：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Blockchain</span>(<span class="params"><span class="built_in">object</span></span>):</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span>(<span class="params">self</span>):</span></span><br><span class="line">        self.chain = []</span><br><span class="line">        self.current_transactions = []</span><br><span class="line">        </span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">new_block</span>(<span class="params">self</span>):</span></span><br><span class="line">        <span class="comment"># Creates a new Block and adds it to the chain</span></span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">new_transaction</span>(<span class="params">self</span>):</span></span><br><span class="line">        <span class="comment"># Adds a new transaction to the list of transactions</span></span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line">    </span><br><span class="line"><span class="meta">    @staticmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">hash</span>(<span class="params">block</span>):</span></span><br><span class="line">        <span class="comment"># Hashes a Block</span></span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="meta">    @property</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">last_block</span>(<span class="params">self</span>):</span></span><br><span class="line">        <span class="comment"># Returns the last Block in the chain</span></span><br><span class="line">        <span class="keyword">pass</span></span><br></pre></td></tr></table></figure>

<p>我们的区块链类负责管理这条链。它将会存储交易且提供一些辅助方法用来增加新的区块到链上。让我们来填充一些函数方法。</p>
<p>一个区块看上去是什么样子的？</p>
<p>每一个区块都拥有一个索引，一个时间戳（Unix时间），一个交易列表，一个证明，以及前一个区块的hash值。</p>
<p>这有一个例子，一个单独的区块看上去是什么样子：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">block = &#123;</span><br><span class="line">    <span class="string">&#x27;index&#x27;</span>: <span class="number">1</span>,</span><br><span class="line">    <span class="string">&#x27;timestamp&#x27;</span>: <span class="number">1506057125.900785</span>,</span><br><span class="line">    <span class="string">&#x27;transactions&#x27;</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="string">&#x27;sender&#x27;</span>: <span class="string">&quot;8527147fe1f5426f9dd545de4b27ee00&quot;</span>,</span><br><span class="line">            <span class="string">&#x27;recipient&#x27;</span>: <span class="string">&quot;a77f5cdfa2934df3954a5c7c7da5df1f&quot;</span>,</span><br><span class="line">            <span class="string">&#x27;amount&#x27;</span>: <span class="number">5</span>,</span><br><span class="line">        &#125;</span><br><span class="line">    ],</span><br><span class="line">    <span class="string">&#x27;proof&#x27;</span>: <span class="number">324984774000</span>,</span><br><span class="line">    <span class="string">&#x27;previous_hash&#x27;</span>: <span class="string">&quot;2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>现在，区块链的思路比较明显—— 每一个新的区块包含它本身，前一个区块的hash。<br>这是至关重要的因为，<strong>这个属性给予了区块链不可变不可篡改的特性：</strong>如果一个攻击者试图攻击了链里较早的一个区块那么后面所有的区块将会包含不正确的hash值。</p>
<p>这是否是有意义的？这是区块链背后的核心理念。</p>
<h3 id="添加交易到区块中"><a href="#添加交易到区块中" class="headerlink" title="添加交易到区块中"></a>添加交易到区块中</h3><p>我们需要一个方法添加交易到区块中。我们的new_transaction()方法负责做这个工作，它非常直接：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Blockchain</span>(<span class="params"><span class="built_in">object</span></span>):</span></span><br><span class="line">    ...</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">new_transaction</span>(<span class="params">self, sender, recipient, amount</span>):</span></span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        Creates a new transaction to go into the next mined Block</span></span><br><span class="line"><span class="string">        :param sender: &lt;str&gt; Address of the Sender</span></span><br><span class="line"><span class="string">        :param recipient: &lt;str&gt; Address of the Recipient</span></span><br><span class="line"><span class="string">        :param amount: &lt;int&gt; Amount</span></span><br><span class="line"><span class="string">        :return: &lt;int&gt; The index of the Block that will hold this transaction</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">        self.current_transactions.append(&#123;</span><br><span class="line">            <span class="string">&#x27;sender&#x27;</span>: sender,</span><br><span class="line">            <span class="string">&#x27;recipient&#x27;</span>: recipient,</span><br><span class="line">            <span class="string">&#x27;amount&#x27;</span>: amount,</span><br><span class="line">        &#125;)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> self.last_block[<span class="string">&#x27;index&#x27;</span>] + <span class="number">1</span></span><br></pre></td></tr></table></figure>

<p>在new_transaction()添加了一个交易到交易列表之后，它将返回 下一个将被挖矿出的区块的索引（当前最后一个区块索引+1）。这对于提交交易的用户，在后面将会非常有用。</p>
<h3 id="创建新的区块"><a href="#创建新的区块" class="headerlink" title="创建新的区块"></a>创建新的区块</h3><p>当我们的区块链被实例化以后，我们将需要播种一个创世区块——一个没有前任的区块。我们同样需要添加一个“proof”变量到我们的创世区块，这是挖矿（工作量证明）的结果。我们将会在后面讨论挖矿。</p>
<p>除了在我们的构造器中创建创世区块以外，我们还要完成new_block(), new_transaction()和hash()几个方法：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">from</span> time <span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Blockchain</span>(<span class="params"><span class="built_in">object</span></span>):</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span>(<span class="params">self</span>):</span></span><br><span class="line">        self.current_transactions = []</span><br><span class="line">        self.chain = []</span><br><span class="line"></span><br><span class="line">        <span class="comment"># Create the genesis block</span></span><br><span class="line">        self.new_block(previous_hash=<span class="number">1</span>, proof=<span class="number">100</span>)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">new_block</span>(<span class="params">self, proof, previous_hash=<span class="literal">None</span></span>):</span></span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        Create a new Block in the Blockchain</span></span><br><span class="line"><span class="string">        :param proof: &lt;int&gt; The proof given by the Proof of Work algorithm</span></span><br><span class="line"><span class="string">        :param previous_hash: (Optional) &lt;str&gt; Hash of previous Block</span></span><br><span class="line"><span class="string">        :return: &lt;dict&gt; New Block</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">        block = &#123;</span><br><span class="line">            <span class="string">&#x27;index&#x27;</span>: <span class="built_in">len</span>(self.chain) + <span class="number">1</span>,</span><br><span class="line">            <span class="string">&#x27;timestamp&#x27;</span>: time(),</span><br><span class="line">            <span class="string">&#x27;transactions&#x27;</span>: self.current_transactions,</span><br><span class="line">            <span class="string">&#x27;proof&#x27;</span>: proof,</span><br><span class="line">            <span class="string">&#x27;previous_hash&#x27;</span>: previous_hash <span class="keyword">or</span> self.<span class="built_in">hash</span>(self.chain[-<span class="number">1</span>]),</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment"># Reset the current list of transactions</span></span><br><span class="line">        self.current_transactions = []</span><br><span class="line"></span><br><span class="line">        self.chain.append(block)</span><br><span class="line">        <span class="keyword">return</span> block</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">new_transaction</span>(<span class="params">self, sender, recipient, amount</span>):</span></span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        Creates a new transaction to go into the next mined Block</span></span><br><span class="line"><span class="string">        :param sender: &lt;str&gt; Address of the Sender</span></span><br><span class="line"><span class="string">        :param recipient: &lt;str&gt; Address of the Recipient</span></span><br><span class="line"><span class="string">        :param amount: &lt;int&gt; Amount</span></span><br><span class="line"><span class="string">        :return: &lt;int&gt; The index of the Block that will hold this transaction</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line">        self.current_transactions.append(&#123;</span><br><span class="line">            <span class="string">&#x27;sender&#x27;</span>: sender,</span><br><span class="line">            <span class="string">&#x27;recipient&#x27;</span>: recipient,</span><br><span class="line">            <span class="string">&#x27;amount&#x27;</span>: amount,</span><br><span class="line">        &#125;)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> self.last_block[<span class="string">&#x27;index&#x27;</span>] + <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="meta">    @property</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">last_block</span>(<span class="params">self</span>):</span></span><br><span class="line">        <span class="keyword">return</span> self.chain[-<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line"><span class="meta">    @staticmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">hash</span>(<span class="params">block</span>):</span></span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        Creates a SHA-256 hash of a Block</span></span><br><span class="line"><span class="string">        :param block: &lt;dict&gt; Block</span></span><br><span class="line"><span class="string">        :return: &lt;str&gt;</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># We must make sure that the Dictionary is Ordered, or we&#x27;ll have inconsistent hashes</span></span><br><span class="line">        block_string = json.dumps(block, sort_keys=<span class="literal">True</span>).encode()</span><br><span class="line">        <span class="keyword">return</span> hashlib.sha256(block_string).hexdigest()</span><br></pre></td></tr></table></figure>

<p>上面的代码应该是直截了当的——我已经加入了一些注释和文档文字来帮助你更加清晰的看懂代码。我们快要完成表示我们的区块链了。但现在，你必须能够理解新的区块是如何被创建的，铸造或者挖矿。</p>
<h3 id="理解工作量证明"><a href="#理解工作量证明" class="headerlink" title="理解工作量证明"></a>理解工作量证明</h3><p>一个工作量证明算法（PoW）是关于新的区块在区块链上如何被创建跟被挖矿的。PoW的目标是找到一个随机数解决一个数学问题。这个随机数必须是比较困难被发现但是很容易被验证的对于网络上的任何人——从计算上来讲。这就是工作量证明背后的核心理念。</p>
<p>我们来看一个非常简单的例子帮助深入理解。</p>
<p>让我们来设计一个 一些整数X乘以Y的hash值必须以0来结尾。<br>所以 hash(x * y) = ac23dc…0。因此对于这个简单的例子，让我们给定x等于5。然后在python里实现：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> hashlib <span class="keyword">import</span> sha256</span><br><span class="line">x = <span class="number">5</span></span><br><span class="line">y = <span class="number">0</span>  <span class="comment"># We don&#x27;t know what y should be yet...</span></span><br><span class="line"><span class="keyword">while</span> sha256(<span class="string">f&#x27;<span class="subst">&#123;x*y&#125;</span>&#x27;</span>.encode()).hexdigest()[-<span class="number">1</span>] != <span class="string">&quot;0&quot;</span>:</span><br><span class="line">    y += <span class="number">1</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&#x27;The solution is y = <span class="subst">&#123;y&#125;</span>&#x27;</span>)</span><br></pre></td></tr></table></figure>

<p>这里的答案是y = 21。因为此时生成的hash是以0结尾的：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">hash</span>(<span class="number">5</span> * <span class="number">21</span>) = 1253e9373e..<span class="number">.5</span>e3600155e860</span><br></pre></td></tr></table></figure>

<p>在比特币里，工作量证明的算法叫做哈希现金（hashcash ）算法。这套算法跟我们上面的例子没有太大的差异，大同小异。这个算法是关于矿工们互相竞赛来创建新的区块。大体上，这个算法的难度是由特定字符在字符串中的数量决定的。当矿工找到答案后，一条带有比特币的交易会奖励给他们。</p>
<p>在比特币网络中可以很容易的验证他们的答案。</p>
<h3 id="实现基本的工作量证明"><a href="#实现基本的工作量证明" class="headerlink" title="实现基本的工作量证明"></a>实现基本的工作量证明</h3><p>我们来为我们的区块链实现一个相似的算法。我们的规则将会跟上面的例子相似：<br>找出一个数字p，与之前的区块的答案做hash函数，使得这个hash是以前置4个0开头的。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> time <span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> uuid <span class="keyword">import</span> uuid4</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Blockchain</span>(<span class="params"><span class="built_in">object</span></span>):</span></span><br><span class="line">    ...</span><br><span class="line">        </span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">proof_of_work</span>(<span class="params">self, last_proof</span>):</span></span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        Simple Proof of Work Algorithm:</span></span><br><span class="line"><span class="string">         - Find a number p&#x27; such that hash(pp&#x27;) contains leading 4 zeroes, where p is the previous p&#x27;</span></span><br><span class="line"><span class="string">         - p is the previous proof, and p&#x27; is the new proof</span></span><br><span class="line"><span class="string">        :param last_proof: &lt;int&gt;</span></span><br><span class="line"><span class="string">        :return: &lt;int&gt;</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">        proof = <span class="number">0</span></span><br><span class="line">        <span class="keyword">while</span> self.valid_proof(last_proof, proof) <span class="keyword">is</span> <span class="literal">False</span>:</span><br><span class="line">            proof += <span class="number">1</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> proof</span><br><span class="line"></span><br><span class="line"><span class="meta">    @staticmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">valid_proof</span>(<span class="params">last_proof, proof</span>):</span></span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?</span></span><br><span class="line"><span class="string">        :param last_proof: &lt;int&gt; Previous Proof</span></span><br><span class="line"><span class="string">        :param proof: &lt;int&gt; Current Proof</span></span><br><span class="line"><span class="string">        :return: &lt;bool&gt; True if correct, False if not.</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">        guess = <span class="string">f&#x27;<span class="subst">&#123;last_proof&#125;</span><span class="subst">&#123;proof&#125;</span>&#x27;</span>.encode()</span><br><span class="line">        guess_hash = hashlib.sha256(guess).hexdigest()</span><br><span class="line">        <span class="keyword">return</span> guess_hash[:<span class="number">4</span>] == <span class="string">&quot;0000&quot;</span></span><br></pre></td></tr></table></figure>

<p>为了调整这个算法的难度，我们可以修改前置0的个数。但4个0是足够的。你会发现添加一个前导0会对解决方案的时间造成巨大的影响。</p>
<p>我们的类接近完成，现在我们准备开始跟HTTP请求打交道了。</p>
<h2 id="第二步：把我们的区块链变成API"><a href="#第二步：把我们的区块链变成API" class="headerlink" title="第二步：把我们的区块链变成API"></a>第二步：把我们的区块链变成API</h2><p>我们将使用Python Flask框架。这是一个Web开发微型框架并且它能够很容易的映射endpoints到python的函数。这使得我们能够把我们的区块链架架设在web上并使用HTTP请求。</p>
<p>我们将创建3个方法：</p>
<ul>
<li>/transactions/new 为区块创建一个新的交易记录</li>
<li>/mine 告诉服务器挖矿一个新的区块</li>
<li>/chain 返回整个区块链</li>
</ul>
<p>设置Flask<br>我们的服务器将在我们的区块链网络中将形成一个单一的节点。现在我们来创建一些样板代码：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">from</span> textwrap <span class="keyword">import</span> dedent</span><br><span class="line"><span class="keyword">from</span> time <span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> uuid <span class="keyword">import</span> uuid4</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> Flask</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Blockchain</span>(<span class="params"><span class="built_in">object</span></span>):</span></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Instantiate our Node</span></span><br><span class="line">app = Flask(__name__)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Generate a globally unique address for this node</span></span><br><span class="line">node_identifier = <span class="built_in">str</span>(uuid4()).replace(<span class="string">&#x27;-&#x27;</span>, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Instantiate the Blockchain</span></span><br><span class="line">blockchain = Blockchain()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&#x27;/mine&#x27;</span>, methods=[<span class="string">&#x27;GET&#x27;</span>]</span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">mine</span>():</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;We&#x27;ll mine a new Block&quot;</span></span><br><span class="line">  </span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&#x27;/transactions/new&#x27;</span>, methods=[<span class="string">&#x27;POST&#x27;</span>]</span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">new_transaction</span>():</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;We&#x27;ll add a new transaction&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&#x27;/chain&#x27;</span>, methods=[<span class="string">&#x27;GET&#x27;</span>]</span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">full_chain</span>():</span></span><br><span class="line">    response = &#123;</span><br><span class="line">        <span class="string">&#x27;chain&#x27;</span>: blockchain.chain,</span><br><span class="line">        <span class="string">&#x27;length&#x27;</span>: <span class="built_in">len</span>(blockchain.chain),</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> jsonify(response), <span class="number">200</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    app.run(host=<span class="string">&#x27;0.0.0.0&#x27;</span>, port=<span class="number">5000</span>)</span><br></pre></td></tr></table></figure>

<p>上面代码的简要解释如下：</p>
<ul>
<li>第15行：实例化我们的节点。了解更多Flask相关知识点击<a target="_blank" rel="noopener" href="http://flask.pocoo.org/docs/0.12/quickstart/#a-minimal-application">这里</a></li>
<li>第18行：为我们的节点创建一个随机的名字。</li>
<li>第21行：实例化我们的区块链类。</li>
<li>第24到26行：创建/mine 路径点，这是一个GET请求。</li>
<li>第28到30行：创建/transactions/new 路径点，这是一个POST请求，因为我们将发送数据到这里。</li>
<li>第32到38行：创建/chain路径点，这里将返回整个区块链。</li>
<li>第40到41行：将服务器运行在5000端口上。</li>
</ul>
<h3 id="Transactions-交易路径"><a href="#Transactions-交易路径" class="headerlink" title="Transactions 交易路径"></a>Transactions 交易路径</h3><p>这是一条交易请求的内容。是由用户发送到服务器的：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line"> <span class="string">&quot;sender&quot;</span>: <span class="string">&quot;my address&quot;</span>,</span><br><span class="line"> <span class="string">&quot;recipient&quot;</span>: <span class="string">&quot;someone else&#x27;s address&quot;</span>,</span><br><span class="line"> <span class="string">&quot;amount&quot;</span>: <span class="number">5</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>因为我们已经添加交易函数到我们的区块上，剩下的步骤就简单了。让我们来写添加交易的函数：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">from</span> textwrap <span class="keyword">import</span> dedent</span><br><span class="line"><span class="keyword">from</span> time <span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> uuid <span class="keyword">import</span> uuid4</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> Flask, jsonify, request</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&#x27;/transactions/new&#x27;</span>, methods=[<span class="string">&#x27;POST&#x27;</span>]</span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">new_transaction</span>():</span></span><br><span class="line">    values = request.get_json()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Check that the required fields are in the POST&#x27;ed data</span></span><br><span class="line">    required = [<span class="string">&#x27;sender&#x27;</span>, <span class="string">&#x27;recipient&#x27;</span>, <span class="string">&#x27;amount&#x27;</span>]</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> <span class="built_in">all</span>(k <span class="keyword">in</span> values <span class="keyword">for</span> k <span class="keyword">in</span> required):</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;Missing values&#x27;</span>, <span class="number">400</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># Create a new Transaction</span></span><br><span class="line">    index = blockchain.new_transaction(values[<span class="string">&#x27;sender&#x27;</span>], values[<span class="string">&#x27;recipient&#x27;</span>], values[<span class="string">&#x27;amount&#x27;</span>])</span><br><span class="line"></span><br><span class="line">    response = &#123;<span class="string">&#x27;message&#x27;</span>: <span class="string">f&#x27;Transaction will be added to Block <span class="subst">&#123;index&#125;</span>&#x27;</span>&#125;</span><br><span class="line">    <span class="keyword">return</span> jsonify(response), <span class="number">201</span></span><br></pre></td></tr></table></figure>

<h3 id="挖矿路径"><a href="#挖矿路径" class="headerlink" title="挖矿路径"></a>挖矿路径</h3><p>我们的挖矿路径是所有魔法开始的地方，它很简单。它需要做3件事情：</p>
<ol>
<li>计算工作量证明</li>
<li>奖励矿工1个金币通过增加一条交易记录</li>
<li>铸造新的区块并增加到区块链中</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> hashlib</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> time <span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> uuid <span class="keyword">import</span> uuid4</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> Flask, jsonify, request</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&#x27;/mine&#x27;</span>, methods=[<span class="string">&#x27;GET&#x27;</span>]</span>)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">mine</span>():</span></span><br><span class="line">    <span class="comment"># We run the proof of work algorithm to get the next proof...</span></span><br><span class="line">    last_block = blockchain.last_block</span><br><span class="line">    last_proof = last_block[<span class="string">&#x27;proof&#x27;</span>]</span><br><span class="line">    proof = blockchain.proof_of_work(last_proof)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># We must receive a reward for finding the proof.</span></span><br><span class="line">    <span class="comment"># The sender is &quot;0&quot; to signify that this node has mined a new coin.</span></span><br><span class="line">    blockchain.new_transaction(</span><br><span class="line">        sender=<span class="string">&quot;0&quot;</span>,</span><br><span class="line">        recipient=node_identifier,</span><br><span class="line">        amount=<span class="number">1</span>,</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Forge the new Block by adding it to the chain</span></span><br><span class="line">    previous_hash = blockchain.<span class="built_in">hash</span>(last_block)</span><br><span class="line">    block = blockchain.new_block(proof, previous_hash)</span><br><span class="line"></span><br><span class="line">    response = &#123;</span><br><span class="line">        <span class="string">&#x27;message&#x27;</span>: <span class="string">&quot;New Block Forged&quot;</span>,</span><br><span class="line">        <span class="string">&#x27;index&#x27;</span>: block[<span class="string">&#x27;index&#x27;</span>],</span><br><span class="line">        <span class="string">&#x27;transactions&#x27;</span>: block[<span class="string">&#x27;transactions&#x27;</span>],</span><br><span class="line">        <span class="string">&#x27;proof&#x27;</span>: block[<span class="string">&#x27;proof&#x27;</span>],</span><br><span class="line">        <span class="string">&#x27;previous_hash&#x27;</span>: block[<span class="string">&#x27;previous_hash&#x27;</span>],</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> jsonify(response), <span class="number">200</span></span><br></pre></td></tr></table></figure>
<p>注意这里已挖矿出的区块的接受者是我们节点的地址。我们完成的大部分工作是与我们的Blockchain类的方法进行交互。就这一点来说，我们已经完成了，现在可以开始与我们的区块链进行交互了。</p>
<h2 id="第三步：与我们的区块链进行交互"><a href="#第三步：与我们的区块链进行交互" class="headerlink" title="第三步：与我们的区块链进行交互"></a>第三步：与我们的区块链进行交互</h2><p>你可以使用普通的cURL或者Postman来与我们的API进行交互。</p>
<p>启动服务器：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ python blockchain.py</span><br><span class="line">* Running on http://<span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">5000</span>/ (Press CTRL+C to quit)</span><br></pre></td></tr></table></figure>

<p>让我们尝试开始挖掘一个新的区块通过发起一个GET请求到<br><a target="_blank" rel="noopener" href="http://localhost:5000/mine">http://localhost:5000/mine</a></p>
<img src="/2021/09/29/learn-blockchains-by-building-one/1.png" class="">

<p>让我们创建一个新的交易通过发起一个POST请求到<br><a target="_blank" rel="noopener" href="http://localhost:5000/transactions/new">http://localhost:5000/transactions/new</a><br>并在请求体里附上交易数据结构</p>
<img src="/2021/09/29/learn-blockchains-by-building-one/2.png" class="">

<p>如果你没有使用Postman, 你可以使用cURL发起相似的请求：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ curl -X POST -H <span class="string">&quot;Content-Type: application/json&quot;</span> -d <span class="string">&#x27;&#123;</span></span><br><span class="line"><span class="string"> &quot;sender&quot;: &quot;d4ee26eee15148ee92c6cd394edd974e&quot;,</span></span><br><span class="line"><span class="string"> &quot;recipient&quot;: &quot;someone-other-address&quot;,</span></span><br><span class="line"><span class="string"> &quot;amount&quot;: 5</span></span><br><span class="line"><span class="string">&#125;&#x27;</span> <span class="string">&quot;http://localhost:5000/transactions/new&quot;</span></span><br></pre></td></tr></table></figure>

<p>我重启了我的服务器，已经挖出了两个区块，总共有3个区块。我们来检查一下整个区块链通过请求<br> <a target="_blank" rel="noopener" href="http://localhost:5000/chain%EF%BC%9A">http://localhost:5000/chain：</a><br> <figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"> &#123;</span><br><span class="line">  <span class="attr">&quot;chain&quot;</span>: [</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">&quot;index&quot;</span>: <span class="number">1</span>,</span><br><span class="line">      <span class="attr">&quot;previous_hash&quot;</span>: <span class="number">1</span>,</span><br><span class="line">      <span class="attr">&quot;proof&quot;</span>: <span class="number">100</span>,</span><br><span class="line">      <span class="attr">&quot;timestamp&quot;</span>: <span class="number">1506280650.770839</span>,</span><br><span class="line">      <span class="attr">&quot;transactions&quot;</span>: []</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">&quot;index&quot;</span>: <span class="number">2</span>,</span><br><span class="line">      <span class="attr">&quot;previous_hash&quot;</span>: <span class="string">&quot;c099bc...bfb7&quot;</span>,</span><br><span class="line">      <span class="attr">&quot;proof&quot;</span>: <span class="number">35293</span>,</span><br><span class="line">      <span class="attr">&quot;timestamp&quot;</span>: <span class="number">1506280664.717925</span>,</span><br><span class="line">      <span class="attr">&quot;transactions&quot;</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="attr">&quot;amount&quot;</span>: <span class="number">1</span>,</span><br><span class="line">          <span class="attr">&quot;recipient&quot;</span>: <span class="string">&quot;8bbcb347e0634905b0cac7955bae152b&quot;</span>,</span><br><span class="line">          <span class="attr">&quot;sender&quot;</span>: <span class="string">&quot;0&quot;</span></span><br><span class="line">        &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">&quot;index&quot;</span>: <span class="number">3</span>,</span><br><span class="line">      <span class="attr">&quot;previous_hash&quot;</span>: <span class="string">&quot;eff91a...10f2&quot;</span>,</span><br><span class="line">      <span class="attr">&quot;proof&quot;</span>: <span class="number">35089</span>,</span><br><span class="line">      <span class="attr">&quot;timestamp&quot;</span>: <span class="number">1506280666.1086972</span>,</span><br><span class="line">      <span class="attr">&quot;transactions&quot;</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="attr">&quot;amount&quot;</span>: <span class="number">1</span>,</span><br><span class="line">          <span class="attr">&quot;recipient&quot;</span>: <span class="string">&quot;8bbcb347e0634905b0cac7955bae152b&quot;</span>,</span><br><span class="line">          <span class="attr">&quot;sender&quot;</span>: <span class="string">&quot;0&quot;</span></span><br><span class="line">        &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">  ],</span><br><span class="line">  <span class="attr">&quot;length&quot;</span>: <span class="number">3</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="第四步：共识"><a href="#第四步：共识" class="headerlink" title="第四步：共识"></a>第四步：共识</h2><p>这是非常酷的。我们已经有了一个基本的区块链能够接受交易和允许大家在上面挖矿。但是整个区块链的重点在于这个系统应该是分散的去中心化的。如果它们是去中心化的，那么怎么确保他们都在维护同一条链条。这叫做共识问题，那么我们将不得不实现一个共识算法如果我们希望更多的不止一个节点在我们的网络上。</p>
<h3 id="注册新的节点"><a href="#注册新的节点" class="headerlink" title="注册新的节点"></a>注册新的节点</h3><p>在我们能够实现一个共识算法之前，我们需要一种方法让一个节点能够知道网络上的其它相邻节点。我们网络中的每一个节点都应该保存一个网络中其它节点的注册表。因此，我们需要更多的路径点：</p>
<ol>
<li>/nodes/register 接受一个新节点的列表以URL的格式</li>
<li>/nodes/resolve 实现我们的共识算法，能解决冲突——保证节点工作在正确的链上</li>
</ol>
<p>我们来修改区块链的构造函数提供一个方法来注册节点：</p>
<figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="keyword">from</span> urllib.parse <span class="keyword">import</span> urlparse</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Blockchain</span>(<span class="params"><span class="built_in">object</span></span>):</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span>(<span class="params">self</span>):</span></span><br><span class="line">        ...</span><br><span class="line">        self.nodes = <span class="built_in">set</span>()</span><br><span class="line">        ...</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">register_node</span>(<span class="params">self, address</span>):</span></span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        Add a new node to the list of nodes</span></span><br><span class="line"><span class="string">        :param address: &lt;str&gt; Address of node. Eg. &#x27;http://192.168.0.5:5000&#x27;</span></span><br><span class="line"><span class="string">        :return: None</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">        parsed_url = urlparse(address)</span><br><span class="line">        self.nodes.add(parsed_url.netloc)</span><br></pre></td></tr></table></figure>

<p>注意我们使用了一个set()集合来保存节点列表。这是一个简便的方法来确保新节点的添加是幂等的——也就是说不管我们添加一个节点多少次，它只存在一个实例，因为set集合里的元素是无序不重复的。</p>
<h3 id="实现共识算法"><a href="#实现共识算法" class="headerlink" title="实现共识算法"></a>实现共识算法</h3><p>就像之前提到的，冲突出现于当一个节点跟其它节点维护了不同的链。为了解决这个问题，我们需要制定一些规则<em>最长有效链是有权威的</em>。用其他话说，网络上的最长链是既成事实的。使用这个算法，网络之中的节点能够达成共识。</p>
<figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Blockchain</span>(<span class="params"><span class="built_in">object</span></span>)</span></span><br><span class="line"><span class="class">    ...</span></span><br><span class="line"><span class="class">    </span></span><br><span class="line"><span class="class">    <span class="title">def</span> <span class="title">valid_chain</span>(<span class="params">self, chain</span>):</span></span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        Determine if a given blockchain is valid</span></span><br><span class="line"><span class="string">        :param chain: &lt;list&gt; A blockchain</span></span><br><span class="line"><span class="string">        :return: &lt;bool&gt; True if valid, False if not</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">        last_block = chain[<span class="number">0</span>]</span><br><span class="line">        current_index = <span class="number">1</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> current_index &lt; <span class="built_in">len</span>(chain):</span><br><span class="line">            block = chain[current_index]</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">f&#x27;<span class="subst">&#123;last_block&#125;</span>&#x27;</span>)</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">f&#x27;<span class="subst">&#123;block&#125;</span>&#x27;</span>)</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&quot;\n-----------\n&quot;</span>)</span><br><span class="line">            <span class="comment"># Check that the hash of the block is correct</span></span><br><span class="line">            <span class="keyword">if</span> block[<span class="string">&#x27;previous_hash&#x27;</span>] != self.<span class="built_in">hash</span>(last_block):</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">            <span class="comment"># Check that the Proof of Work is correct</span></span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> self.valid_proof(last_block[<span class="string">&#x27;proof&#x27;</span>], block[<span class="string">&#x27;proof&#x27;</span>]):</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">            last_block = block</span><br><span class="line">            current_index += <span class="number">1</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">resolve_conflicts</span>(<span class="params">self</span>):</span></span><br><span class="line">        <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">        This is our Consensus Algorithm, it resolves conflicts</span></span><br><span class="line"><span class="string">        by replacing our chain with the longest one in the network.</span></span><br><span class="line"><span class="string">        :return: &lt;bool&gt; True if our chain was replaced, False if not</span></span><br><span class="line"><span class="string">        &quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">        neighbours = self.nodes</span><br><span class="line">        new_chain = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># We&#x27;re only looking for chains longer than ours</span></span><br><span class="line">        max_length = <span class="built_in">len</span>(self.chain)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># Grab and verify the chains from all the nodes in our network</span></span><br><span class="line">        <span class="keyword">for</span> node <span class="keyword">in</span> neighbours:</span><br><span class="line">            response = requests.get(<span class="string">f&#x27;http://<span class="subst">&#123;node&#125;</span>/chain&#x27;</span>)</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> response.status_code == <span class="number">200</span>:</span><br><span class="line">                length = response.json()[<span class="string">&#x27;length&#x27;</span>]</span><br><span class="line">                chain = response.json()[<span class="string">&#x27;chain&#x27;</span>]</span><br><span class="line"></span><br><span class="line">                <span class="comment"># Check if the length is longer and the chain is valid</span></span><br><span class="line">                <span class="keyword">if</span> length &gt; max_length <span class="keyword">and</span> self.valid_chain(chain):</span><br><span class="line">                    max_length = length</span><br><span class="line">                    new_chain = chain</span><br><span class="line"></span><br><span class="line">        <span class="comment"># Replace our chain if we discovered a new, valid chain longer than ours</span></span><br><span class="line">        <span class="keyword">if</span> new_chain:</span><br><span class="line">            self.chain = new_chain</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">False</span></span><br></pre></td></tr></table></figure>
    </div>

    
    
    

      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2021/09/29/hex-editor/" rel="prev" title="16进制编辑器">
      <i class="fa fa-chevron-left"></i> 16进制编辑器
    </a></div>
      <div class="post-nav-item"></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          Table of Contents
        </li>
        <li class="sidebar-nav-overview">
          Overview
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AC%AC%E4%B8%80%E6%AD%A5%EF%BC%9A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%8C%BA%E5%9D%97%E9%93%BE"><span class="nav-number">1.</span> <span class="nav-text">第一步：创建一个区块链</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%A1%A8%E7%8E%B0%E4%B8%80%E4%B8%AA%E5%8C%BA%E5%9D%97%E9%93%BE"><span class="nav-number">1.1.</span> <span class="nav-text">表现一个区块链</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%B7%BB%E5%8A%A0%E4%BA%A4%E6%98%93%E5%88%B0%E5%8C%BA%E5%9D%97%E4%B8%AD"><span class="nav-number">1.2.</span> <span class="nav-text">添加交易到区块中</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%88%9B%E5%BB%BA%E6%96%B0%E7%9A%84%E5%8C%BA%E5%9D%97"><span class="nav-number">1.3.</span> <span class="nav-text">创建新的区块</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%90%86%E8%A7%A3%E5%B7%A5%E4%BD%9C%E9%87%8F%E8%AF%81%E6%98%8E"><span class="nav-number">1.4.</span> <span class="nav-text">理解工作量证明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AE%9E%E7%8E%B0%E5%9F%BA%E6%9C%AC%E7%9A%84%E5%B7%A5%E4%BD%9C%E9%87%8F%E8%AF%81%E6%98%8E"><span class="nav-number">1.5.</span> <span class="nav-text">实现基本的工作量证明</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AC%AC%E4%BA%8C%E6%AD%A5%EF%BC%9A%E6%8A%8A%E6%88%91%E4%BB%AC%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E5%8F%98%E6%88%90API"><span class="nav-number">2.</span> <span class="nav-text">第二步：把我们的区块链变成API</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Transactions-%E4%BA%A4%E6%98%93%E8%B7%AF%E5%BE%84"><span class="nav-number">2.1.</span> <span class="nav-text">Transactions 交易路径</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8C%96%E7%9F%BF%E8%B7%AF%E5%BE%84"><span class="nav-number">2.2.</span> <span class="nav-text">挖矿路径</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AC%AC%E4%B8%89%E6%AD%A5%EF%BC%9A%E4%B8%8E%E6%88%91%E4%BB%AC%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E8%BF%9B%E8%A1%8C%E4%BA%A4%E4%BA%92"><span class="nav-number">3.</span> <span class="nav-text">第三步：与我们的区块链进行交互</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AC%AC%E5%9B%9B%E6%AD%A5%EF%BC%9A%E5%85%B1%E8%AF%86"><span class="nav-number">4.</span> <span class="nav-text">第四步：共识</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%B3%A8%E5%86%8C%E6%96%B0%E7%9A%84%E8%8A%82%E7%82%B9"><span class="nav-number">4.1.</span> <span class="nav-text">注册新的节点</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AE%9E%E7%8E%B0%E5%85%B1%E8%AF%86%E7%AE%97%E6%B3%95"><span class="nav-number">4.2.</span> <span class="nav-text">实现共识算法</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">李工</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">4</span>
          <span class="site-state-item-name">posts</span>
        </a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2021</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">李工</span>
</div>
  <div class="powered-by">Powered by <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://mist.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Mist</a>
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/muse.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

</body>
</html>
